
package carremagique;

import java.io.*;
import java.util.*;

public class Carremagique 
{
    public static final int NMAX = 10; // Taille maximum du carré
    int [][] carre; //Tableau double d'int stockant le carré
    int n; // Taille effective du carré
    
    public Carremagique() //constructeur
    {
        carre = new int[NMAX][NMAX]; // Le carré est créé en mémoire avec une taille nmax
    }
    public void afficherMatrice() //Fonction permettant d'afficher le carré
    {

        for(int i=0;i<n;i++) //Boucle pour chaque ligne du carré
            {
                for(int j=0;j<n;j++) //Boucle pour chaque colonne du carré
                {
                    System.out.print(carre[i][j]+" ");//Afficher chaque case et un espace entre chaque
                }
                System.out.println(""); // Revenir à la ligne pour afficher la ligne suivante
            }
    }
    public void lireMatrice(String type) throws FileNotFoundException, IOException /* Fonction permettant de remplir le carré, 
                                                                                    en le tapant au clavier ou en le lisant dans un
                                                                                    fichier (d'où le type en argument)*/
    {                                                                                          
        
        if (type.equals("c")) // Cas d'un remplissage par saisie au clavier
        {
           boolean ok=true; //Booléen servant pour le contrôle de la saisie de la taille
           boolean ok2=true;//Booléen servant pour le contrôle de la saisie du carré
           Scanner sc= new Scanner(System.in); //Scanner servant aux saisies
           do
           {
            try
                {
            sc= new Scanner(System.in);        
            ok=true;   //Pour sortir de la boucle s'il n'y a pas d'erreur 
            System.out.println("Entrez le nombre de lignes ou de colonnes (<=10) :");
            n=sc.nextInt();
                } //Toute autre saisie qu'un entier génèrera une exception
                        
            catch(InputMismatchException e) // Attraper les exceptions générées par une mauvaise saisie
               {
                ok=false; //Pour repasser dans la boucle et entrer une nouvelle taille
                System.out.println("La valeur doit être un entier");
                n=1; /* Après tests, un nombre invalide semble être considéré comme négatif ou nul si on s'en sert lors d'une 
                        comparaison.Cette ligne sert à ne pas afficher l'avertissement "La valeur doit être strictement positive"
                        (voir plus bas) lors de la saisie d'une valeur de mauvais type. */
               }
            if (n>NMAX)
                {
               ok=false;
               System.out.println("La valeur ne doit pas être supérieure à " +NMAX);//La taille doit être inférieure ou égale à nmax
                }
            
            if (n<=0)
                {
                ok=false;
                System.out.println("La valeur doit être strictement positive"); //Une taille négative ou nulle n'a pas de sens.
                }

            
           }while(!ok); // Boucle tant que la taille saisie n'est pas valide (0< taille <= 10)
           do //boucle 1
           {
            System.out.println("Entrez la matrice");
             sc= new Scanner(System.in);
            for(int i=0;i<n;i++) //boucle 2
            {
                for(int j=0;j<n;j++)//boucle 3
                {                    
                        try
                        {
                        ok2=true; //Sortir de la boucle s'il n'ya pas d'erreur
                        carre[i][j]=sc.nextInt();
                        } // Toute autre saisie qu'un entier génèrera une exception
                                        
                        catch(InputMismatchException e)//En cas d'erreur de saisie
                        {
                        ok2=false; //Pour repasser dans la boucle 1 et retaper la matrice
                        System.out.println("Les valeurs doivent toutes être des entiers.");
                        j=n; //Pour sortir de la boucle 3
                        i=n; // Pour sortir de la boucle 2. Ces sorties de boucle sont nécessaires pour recommencer la boucle 1.
                        }

               }
            }
           }while(!ok2);//Boucle tant que la matrice n'est pas entièrement remplie d'entiers
        }
        else if(type.equals("d"))// Cas du choix d'un autre périphérique
            {
                String [] ligne; //Tableau de strings destiné à contenir chaque ligne une par une
                File fic=new File("magique.txt"); // Fichier d'ou on lit le carré
                BufferedReader buffer = new BufferedReader(new FileReader(fic)); //Buffer pour lire le fichier 
                n=(buffer.readLine().split(" ")).length;/*Sert à déterminer la taille de la matrice. Découpe la première ligne avec 
                 *                                        l'espace pour séparateur. Compte le nombre de chaînes ainsi créées (nombre 
                 *                                         de colonnes). La taille de la matrice est ce nombre*/
                carre=new int[n][n]; //Création du carré connaissant la taille
                buffer=new BufferedReader(new FileReader(fic));  //Réinitialisation du buffer car il a déja parcouru une ligne
                for(int i=0;i<n;i++) //Boucle pour chaque ligne
                {     
                    ligne=buffer.readLine().split(" ");//Chaque nombre de la ligne est mis dans le tableau ligne (en tant que string)
                    for(int j=0;j<n;j++)//Boucle pour chaque colonne
                    {
                        carre[i][j]=Integer.parseInt(ligne[j]);//Chaque string de ligne est convertie en nombre et placée dans le carré
                    }
                }
                buffer.close();
        
                  
        }
        else // Cas d'un autre choix autre que c ou d (qui n'est donc pas une option valide)
        {
            System.out.println("Cette option n'existe pas");
        }
    }
    
    public int calculerSomme(int num, String type) //Calcule la somme d'une ligne/colonne/diagonale. La diagonale descendante étant la n°1
    {
        int somme=0;
        if (type.equals("Colonne"))//Cas d'une colonne
            
        {
            for(int i=0;i<n;i++)//Boucle pour chaque ligne
            {
                somme=somme+carre[i][num];//Le numéro de colonne est fixée, et on en somme chaque ligne
            }
         
        }
        if (type.equals("Ligne"))//Cas d'une colonne
        {
            for (int i=0;i<n;i++)//Boucle pour chaque colonne
            {
                somme=somme+carre[num][i];//Le numéro de ligne est fixé, et on en somme chaque colonne
            }
          
        }
        if (type.equals("Diagonale"))//Cas d'une diagonale
        {
            if(num==1)//Cas de la diagonale descendante
            {
                for(int i=0;i<n;i++)//Boucle pour chaque nombre de la diagonale
                {
                    somme=somme+carre[i][i];//Les nombres de la diagonale descendante sont ceux dont numéro_ligne=numéro_colonne
                }
            }
            else //Cas de la diagonale ascendante
            {
                for(int i=0;i<n;i++) // Boucle pour chaque nombre de la diagonale
                {
                    somme=somme+carre[n-1-i][i];/*On part de la dernière ligne et de la première colonne, 
                     *                           on décrémente le numéro de ligne et on incrémente 
                                                 le numéro de colonne à chaque passage.*/                
                }
            }
        }
        return somme;
    }
    public boolean estUnCarreMagique()//Vérifie la somme de chaque ligne/colonne/diagonale. Retourne vrai si le carré est magique
    {
        int i=0;//Compteur servant plus tard à parcourir chaque ligne puis chaque colonne
        int somme;//Somme de la première diagonale, qui sera comparée à chaque somme de ligne/colonne/diagonale
        int comparaison;//Somme de chaque ligne/colonne et de la deuxième diagonale.
        somme=calculerSomme(1,"Diagonale");
        System.out.println("Somme de la première diagonale: "+somme);
        comparaison=calculerSomme(2,"Diagonale");
        System.out.println("Somme de la deuxième diagonale: "+comparaison);
        if(comparaison!=somme)//Compare la somme de la deuxième diagonale à celle de la première
            {return false;}//Si les sommes diffèrent, le carré n'est pas magique
        while(i<n)// Boucle pour chaque ligne
        {
            comparaison=calculerSomme(i,"Ligne");
            System.out.println("Somme de la ligne numéro "+(i+1)+": "+comparaison);
            if (comparaison!=somme)//Compare la somme de la ligne courante à celle de la première diagonale
                {return false;}//Si les sommes diffèrent, le carré n'est pas magique
            i++;
        }   
        
        i=0;
        while(i<n)//Boucle pour chaque colonne
        {
            comparaison=calculerSomme(i,"Colonne");
            System.out.println("Somme de la colonne numéro "+(i+1)+": "+comparaison);
            if (comparaison!=somme)//Compare la somme de la colonne courante à celle de la première diagonale
                {return false;}//Si les sommes diffèrent, le carré n'est pas magique
            i++;
        }   
        return true;// Si on arrive à cette ligne, toutes les sommes sont égales, le carré est donc magique.
    }
    
    
        public static void main(String[] args) throws IOException 
        {
            Scanner sca = new Scanner(System.in);//Scanner servant à la saisie du de recommencer ou non
            do
            {
            Carremagique carre = new Carremagique();
            String c;//Chaine servant à conserver le choix du mode de remplissage de la matrice
            System.out.println("Entrez c pour clavier ou d pour autre périphérique");
            Scanner s=new Scanner(System.in);//Scanner servant à saisir le choix du mode de remplissage de la matrice
            c=s.nextLine();
            c=c.toLowerCase();
            carre.lireMatrice(c);//Remplit la matrice dans le mode demandé
            if("cd".contains(c))// Si le choix de mode était valide
            {
                System.out.println("Matrice tapée: ");
                carre.afficherMatrice();
                if(carre.estUnCarreMagique())//Si le carré est magique
                {
                    System.out.println("LE CARRE EST UN CARRE MAGIQUE !!!");
                }
                else
                {
                    System.out.println("LE CARRE N'EST PAS UN CARRE MAGIQUE :(");
                }
            }
            
            System.out.println("Recommencer ? o/n");
            }
            
            while(!sca.nextLine().equalsIgnoreCase("n") );//Boucle tant que l'utilisateur n'entre pas 'n' pour ne pas recommencer
            System.out.print("Lol");
        }
}
